package com.my.springboot.tuling.concurrent.cas;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.atomic.AtomicStampedReference;
import java.util.concurrent.locks.LockSupport;

/**
 *reference即我们实际存储的变量，stamp是版本，每次修改可以通过+1保证版本唯一性。这样
 * 就可以保证每次修改后的版本也会往上递增。
 */
@Slf4j
public class AtomicStampedReferenceTest {
    public static void main(String[] args) {
        // 定义AtomicStampedReference Pair.reference值为1, Pair.stamp为1
        AtomicStampedReference atomicStampedReference = new AtomicStampedReference(1,1);
        new Thread(() ->{
            int[] stampHolder = new int[1];
            int value = (int)atomicStampedReference.get(stampHolder);
            int stamp = stampHolder[0];
            log.debug(("Thread1 read value: " + value + ", stamp: " + stamp));

            // 阻塞1s
            LockSupport.parkNanos(1000000000L);
            // Thread1通过CAS修改value值为3
            if(atomicStampedReference.compareAndSet(value,3,stamp, stamp+1)){
                log.debug("Thread1 update from " + value + " to 3");
            } else {
                log.debug("Thread1 update fail!");
            }
        },"Thread1").start();

        new Thread(() ->{
            int[] stampHolder = new int[1];
            int value = (int)atomicStampedReference.get(stampHolder);
            int stamp = stampHolder[0];
            log.debug(("Thread2 read value: " + value + ", stamp: " + stamp));
            // Thread2通过CAS修改value值为2
            if(atomicStampedReference.compareAndSet(value,2,stamp, stamp+1)){
                log.debug("Thread2 update from " + value + " to 2");
                // do something
                value = (int)atomicStampedReference.get(stampHolder);
                stamp = stampHolder[0];
                log.debug("Thread2 read value " + value + ", stamp: " + stamp);
                // Thread2通过CAS修改value值为1
                if(atomicStampedReference.compareAndSet(value,1,stamp, stamp+1)){
                    log.debug("Thread2 update from " + value + " to 1");
                }
            }
        },"Thread2").start();
    }
}
